using System;
using System.Linq.Expressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using FluentSilverlight.Expressions.Font;
using FluentSilverlight.Utility.Reflection;

namespace FluentSilverlight.Expressions.TextItems
{
    public class TextBlockExpression<TModel> : FrameworkElementExpression<TextBlockExpression<TModel>, TModel, TextBlock>
        where TModel : class
    {
        private readonly Accessor accessor;
        private readonly string text;
        private SolidColorBrush foreground = new SolidColorBrush(Colors.Black);
        private double fontSize = 11;
        private FontWeight fontWeight = FontWeights.Normal;
        private BindingMode bindingMode = BindingMode.OneWay;
        private TextAlignment textAlignment;
        private Expression<Func<TModel, object>> textExpression;

        public TextBlockExpression(Expression<Func<TModel, object>> expression)
        {
            textExpression = expression;
            accessor = ReflectionHelper.GetAccessor(expression);
            HorizontalAlignment.Left();
            Name(string.Format("{0}_{1}", accessor.Name, Guid.NewGuid()));
        }

        public TextBlockExpression(string text)
            : this(string.Format("TextBlock_{0}", Guid.NewGuid()), text)
        {}

        public TextBlockExpression(string name, string text) : base(name)
        {
            this.text = text;
            HorizontalAlignment.Left();
        }

        public TextAlignmentExpression<TextBlockExpression<TModel>> TextAlignment
        {
            get { return new TextAlignmentExpression<TextBlockExpression<TModel>>(this, b => textAlignment = b); }
        }

        public TextBlockExpression<TModel> Foreground(Color color)
        {
            this.foreground = new SolidColorBrush(color);
            return thisInstance();
        }

        public TextBlockExpression<TModel> FontSize(double size)
        {
            this.fontSize = size;
            return thisInstance();
        }

        public FontWeightExpression<TextBlockExpression<TModel>> FontWeight
        {
            get { return new FontWeightExpression<TextBlockExpression<TModel>>(thisInstance(), fw => fontWeight = fw); }
        }

        public BindModeExpression<TextBlockExpression<TModel>> Binding
        {
            get { return new BindModeExpression<TextBlockExpression<TModel>>(this, b => bindingMode = b); }
        }

        protected override TextBlockExpression<TModel> thisInstance()
        {
            return this;
        }

        protected override void BuildUp(TextBlock element)
        {
            base.BuildUp(element);

            if (accessor != null)
            {
                propertyBinder.SetBinding(textExpression, TextBlock.TextProperty, bindingMode);
            }
            else
            {
                element.Text = text;
            }

            element.TextAlignment = textAlignment;
            element.Foreground = foreground;
            element.FontSize = fontSize;
            element.FontWeight = fontWeight;
        }

        public static implicit operator TextBlock(TextBlockExpression<TModel> expression)
        {
            var textBlock = new TextBlock();
            expression.BuildUp(textBlock);

            return textBlock;
        }
    }
}